//=============================================================================
// ProMesh.NET - .NET Web Application Framework 
//
// Copyright (c) 2003-2008 Philippe Leybaert
//
// Permission is hereby granted, free of charge, to any person obtaining a copy 
// of this software and associated documentation files (the "Software"), to deal 
// in the Software without restriction, including without limitation the rights 
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
// copies of the Software, and to permit persons to whom the Software is 
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in 
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//=============================================================================

using System;
using System.Collections.Generic;

namespace Activa.ProMesh
{
	public class Router
	{
		private readonly List<Route> _routes = new List<Route>();
		private readonly Dictionary<string,RouteResult> _routeCache = new Dictionary<string, RouteResult>();
		private readonly object _routeCacheLock = new object();

        private bool _useDefaultRoutes = true;

        internal Router()
		{
		}

	    public bool UseDefaultRoutes
	    {
	        get { return _useDefaultRoutes; }
	        set { _useDefaultRoutes = value; }
	    }

	    internal void AddDefaultRoutes()
        {
            if (UseDefaultRoutes)
            {
                AddRoute(new Route("{controller}" + WebAppConfig.PageExtension + "/{action}/{id}", "{controller}","{action}"));
                AddRoute(new Route("{controller}" + WebAppConfig.PageExtension + "/{action}", "{controller}", "{action}"));
                AddRoute(new Route("{controller}" + WebAppConfig.PageExtension, "{controller}", "Run"));
            }

            InsertRoute(new Route("{controller}_ajax" + WebAppConfig.PageExtension + "/{action}", "{controller}", "{action}"));
        }

        public void AddRoute(Route route)
        {
            _routes.Add(route);

            _routeCache.Clear();
        }

		public void InsertRoute(Route route)
		{
			_routes.Insert(0, route);

			_routeCache.Clear();
		}

        public void AddRoute(string url, string controller, string action, IEnumerable<RouteValidator> validators, IEnumerable<RouteParameter> routeParameters)
		{
            AddRoute(new Route(url, controller, action, validators, routeParameters));
		}

        public void InsertRoute(string url, string controller, string action, IEnumerable<RouteValidator> validators, IEnumerable<RouteParameter> routeParameters)
		{
            InsertRoute(new Route(url, controller, action, validators, routeParameters));
		}

        public void AddRoute(string url, string controller, string action, params RouteParameter[] routeParameters)
        {
            AddRoute(new Route(url, controller, action, routeParameters));
        }

        public void InsertRoute(string url, string controller, string action, params RouteParameter[] routeParameters)
        {
            InsertRoute(new Route(url, controller, action, routeParameters));
        }

        public void AddRoute(string url, string controller, string action, IEnumerable<RouteParameter> routeParameters)
		{
            AddRoute(new Route(url, controller, action, routeParameters));
        }

        public void InsertRoute(string url, string controller, string action, IEnumerable<RouteParameter> routeParameters)
		{
            InsertRoute(new Route(url, controller, action, routeParameters));
        }

        public void AddRoute(string url, string controller, IEnumerable<RouteValidator> validators, IEnumerable<RouteParameter> routeParameters)
        {
            AddRoute(new Route(url, controller, validators, routeParameters));
        }

        public void InsertRoute(string url, string controller, IEnumerable<RouteValidator> validators, IEnumerable<RouteParameter> routeParameters)
        {
            InsertRoute(new Route(url, controller, validators, routeParameters));
        }

        public void AddRoute(string url, string controller, params RouteParameter[] routeParameters)
        {
            AddRoute(new Route(url, controller, routeParameters));
        }

        public void InsertRoute(string url, string controller, params RouteParameter[] routeParameters)
        {
            InsertRoute(new Route(url, controller, routeParameters));
        }

        public void AddRoute(string url, string controller, IEnumerable<RouteParameter> routeParameters)
        {
            AddRoute(new Route(url, controller, routeParameters));
        }

        public void InsertRoute(string url, string controller, IEnumerable<RouteParameter> routeParameters)
        {
            InsertRoute(new Route(url, controller, routeParameters));
        }

        public void AddRoute(string url, string controller, string action) 
        {
            AddRoute(new Route(url, controller, action));
        }

        public void InsertRoute(string url, string controller, string action)
        {
            AddRoute(new Route(url, controller, action));
        }

        public void AddRoute(string url, string controller) 
        {
            AddRoute(new Route(url, controller));
        }

		internal RouteResult Resolve(string url)
		{
			RouteResult result;

			lock (_routeCacheLock)
			{
				if (_routeCache.TryGetValue(url, out result))
					return result;
			}

			foreach (Route route in _routes)
			{
				result = route.Resolve(url);

				if (result != null)
				{
					lock (_routeCacheLock)
					{
						if (!_routeCache.ContainsKey(url))
							_routeCache[url] = result;
					}

					return result;
				}
			}

			return null;
		}

	}
}